"""
@-*- coding: utf-8 -*-
@ python：python 3.8
@ 创建人员：ylx
@ 创建时间：2025/2/25 下午6:24
@ 内容：
"""
"""
在 Python 中，类表示具有相同属性和方法的对象的集合。
在使用类时，需要先定义类，然后再创建类的实例，通过类的实例就可以访问类中的属性和方法了

定义完类后，并不会真正创建一个实例。这有点像一个汽车的设计图。设计图可以告诉你汽车看上去什么样，但设计图本身不是一个汽车。
你不能开走它，它只能用来建造真正的汽车，而且可以使用它制造很多辆汽车。那么如何创建实例呢？

class 语句本身并不创建该类的任何实例。所以在类定义完成以后，可以创建类的实例，
即实例化该类的对象。类名(参数)
类名用于指定具体的类，后面的参数是可选参数，当你创建一个类时，如果没有__init__()方法或者
__init__()方法只有self一个参数时，此时你实例化这个类时可以不传参

class Bird:
    pass
    
pigeon = Bird()
print(pigeon) #从结果可以看出pigeon是Bird类的实例


创建类后，你可以手动创建一个__init__()方法，这是一个特殊方法，特殊之处就是在实例化类时，python都会先自动执行它
__init__()方法必须包含一个self参数，且必须是第一个参数，self参数是一个指向实例本身的引用，用于访问类中的属性和方法
在方法调用时会自动传递实际参数self，所以如果当__init__()方法只有1个参数时，在创建类的实例时，就不需要指定实际参数了
比如：
class Bird:
    def __init__(self):
        print('这是鸟类')
        

    
pigeon = Bird() #打印输出 我是鸟类
根据上述运行来看，创建鸟类实例时，虽然没有给__init__()方法指定参数，但是该方法会自动执行
在__init__()方法中，我们除了首位的self参数外还可以增加其他参数，使用逗号分开

class Apple:
    def __init__(self, color, shape):
        print('这是苹果')
        print(color)
        print(shape)

color1 = 'red'
shape1 = 'square'
apple_1 = Apple(color1,shape1)
这种写法仅仅只是让color1 shape1 作为局部变量出现，既出现打印后无法再次使用，比如说其他
类方法想调用相关属性时，是无法使用实例属性的，继续看下面优化后的写法
self.color = color 这种就类似给属性打了标记或者颁发一个身份证，使得在类作用域内，大家都能找到并使用它


class Apple:
    def __init__(self, color, shape):
        self.color = color
        self.shape = shape
        print('这是苹果')
        print(self.color)
        print(self.shape)
这段代码是可以运行的，self.color self.shape将传入的参数color和shape分别赋值给实例属性
self.color  self.shape
我们可以做如下改进，让模块更加清楚-将打印内容单独拆成一个方法，__init__()应该只负责初始化对象状态，而不应该有其他的作用
增加文档字符串，帮助他人理解你的代码功能
class Apple:
"""
#表示一个苹果类
"""
    def __init__(self, color, shape):
"""
# 初始化苹果对象
# 仅仅配置属性，不做相关操作，除非是调用比如说日志打印，记录实例生成等，否则不应该做过多的操作
# :param color :苹果的颜色
# :param shape:苹果的形状
"""
        self.color = color
        self.shape = shape

# 开始写方法，这些类方法就是逻辑中需要的各个环节，这些里边就是你操作数据的做法
    def describe(self):
        print('这是苹果')
        print(self.color)
        print(self.shape)

# 实例化类对象
apple = Apple('red', 'square')
# 调用实例方法
apple.describe()

***我们看到单独的函数是def定义的，类中的方法也是def定义的，有什么区别
类里，实例方法和python中函数的主要区别就是
函数实现的是某个独立的功能
类实例方法是实现了类中的一个行为，是类的一部分




类中声明的变量通常被称为类属性，类属性和实例属性是有区别的
实例属性只能通过实例名访问，如果通过类名访问实例属性，就会报错
实例属性通过实例名称修改，与类属性不同，实例名称修改实例属性后，不影响该类中另一个实例中相应的实例属性值
因为实例属性是属于这个实例对象的，它和另外的实例对象是隔离开的

class People:  # 创建一个人类
"""
#人类
"""
    def __init__(self):  # 构造方法
        self.eye = '有两只眼睛'
        print('我属于人类，我有以下特征:')
        print(self.eye)  # 输出眼睛特征
        
        
man_1 = People()  # 创建People类的实例1
man_2 = People()  # 创建People类的实例2
man_1.eye = '有两只圆圆的大眼睛'  # 修改实例属性
print('man_1的eye属性:', man_1.eye)
print('man_2的eye属性:', man_2.eye)


打印
我属于人类，我有以下特征:
有两只眼睛
我属于人类，我有以下特征:
有两只眼睛
man_1的eye属性: 有两只圆圆的大眼睛
man_2的eye属性: 有两只眼睛



为了保证类内部的某些属性或方法不被外部所访问，可以在属性或方法名前面添加双下划线（__eye）或首尾添加双下划线（__eye__），
首尾双下划线一般是魔法方法，一般不建议这样，如果要私有，前面加下划线即可
从而限制访问权限。其中，双下划线、首尾双下划线的作用如下

双下划线表示 private（私有）类型的成员，只允许定义该方法的类本身进行访问，而且也不能通过类的实例进行访问
但是可以通过 “类的实例名._类名__xxx” 方式访问。
class People:  # 创建一个人类
    __eye = '有两只眼睛'
    def __init__(self):  # 构造方法
        print('__init__():', People.__eye)  # 在实例方法中访问私有属性
man = People()  # 创建People类的实例
print('加入类名:', man._People__eye)  # 私有属性，可以通过"实例名._类名__xxx"方式访问
print('直接访问:', man.__eye)  # 私有属性不能通过实例名访问，出错


类属性
类中声明变量格式如下：
class Base_Class:
    age = 18
    
在类中直接声明的变量称为类的属性
类属性属于类本身，而不是某个具体的实例。
所有该类的实例共享同一个类属性。
可以通过类名或实例访问类属性，但通过实例修改类属性时需要小心（可能会创建同名的实例属性）。
class MyClass:
    class_variable = "我是类属性"  # 类属性

# 通过类名访问类属性
print(MyClass.class_variable)  # 输出: 我是类属性

# 创建类的实例
obj1 = MyClass()
obj2 = MyClass()

# 通过实例访问类属性
print(obj1.class_variable)  # 输出: 我是类属性
print(obj2.class_variable)  # 输出: 我是类属性

# 修改类属性（通过类名）
MyClass.class_variable = "修改后的类属性"
print(MyClass.class_variable)  # 输出: 修改后的类属性
print(obj1.class_variable)     # 输出: 修改后的类属性
print(obj2.class_variable)     # 输出: 修改后的类属性

# 如果通过实例修改类属性，实际上会创建一个同名的实例属性
obj1.class_variable = "实例属性"
print(obj1.class_variable)  # 输出: 实例属性 (实际上是实例属性)
print(obj2.class_variable)  # 输出: 修改后的类属性 (仍然是类属性)


实例属性，是指在类的实例方法中通过self声明的变量称为实例属性
实例属性属于具体的实例，每个实例都有自己的实例属性。
不同实例之间的实例属性互不干扰。
class MyClass:
    def __init__(self, value):
        self.instance_variable = value  # 实例属性

# 创建两个实例
obj1 = MyClass("实例1的属性")
obj2 = MyClass("实例2的属性")

# 访问实例属性
print(obj1.instance_variable)  # 输出: 实例1的属性
print(obj2.instance_variable)  # 输出: 实例2的属性

# 修改实例属性
obj1.instance_variable = "修改后的实例1属性"
print(obj1.instance_variable)  # 输出: 修改后的实例1属性
print(obj2.instance_variable)  # 输出: 实例2的属性 (不受影响)


                    类属性         实例属性
所属对象    属于类                 属于实例
生命周期    类加载时创建，直到程序结束       实例创建时创建，实例销毁时消失
访问方式    类名.属性名   实例名.属性名       实例名.属性名
共享性     所有实例共享                      每个实例独立
修改影响范围  修改影响所有实例            修改只影响当前实例





如何理解类中的self的作用
self代表了类实例本身，在类中，用于引用实例本身,指代类的实例对象本身，用于访问实例的属性
和其他方法，通过self可以在类的方法内部访问和修改实例属性
简单的来说self，就是指代对象自己，哪个实例调用这个方法，那么self就是表示这个实例


对于class，我们可以把它看做一个组装工厂，加入，比如我们要生产，先安装胳膊，再安装头，然后
我们这个流水线上，这些数量是可以调整的
class BuildRobot():
    def __init__(self,armcount,headcount):
        self.armcount = armcount
        self.headcount = headcount

这里的class就是搭建了一个BuildRobot的工厂，里边的__init__方法就是为了告诉这个机器人工厂里生产机器人
的流水线，我这个机器人有几个胳膊，几个脑袋
如果我们只是简单的搭建好了class，此时run一下，是没有任何输出的，并没有开始生产，要想生产这个产品
就要看下面的instance（实例），这个就可以理解为工厂生产出来的一个机器人比如2个胳膊，一个脑袋
normal_robot = BuildRobot(2,1)
normal_robot.armcount #访问实例属性
normal_robot.headcount    
我们还可以生产其他规格的机器人
weird_robot = BuildRobot(4,1)
上述生产的机器人，我们都称之为instance，虽然胳膊和头的数量不同，但是本质上都是这个工厂生产的    
        
        
我们现在要给生产出来的机器人胳膊上色，我们装一个车间
def paintarm(self,color)
    print("paint arm:",color)      
    
这就是类中的方法

normal_robot.paintarm("red") ---这样我们就给机器人上色了
总结下：如果没有先制造这个机器人，这个车间无法完成上色，所以method是依赖instance的
这个车间只能给这个工厂生产的机器人上色，别的工厂的制造过来的无法上色，所以method是依赖于class的
只有这个class创建的instance，才能调用这个method

但是你会说，那我把上色的或外包了，假如说我在类外专门来一个上色的函数，function
无论你给我是这个工厂的机器人还是那个工厂的机器狗我都拿来，可以给胳膊上色，这就是function和method的区别
def out_paint(robot, color):
    print('paint',robot,"arm",color)




类中的方法一种是实例方法，一种是类方法，依赖@classmethod类装饰器来实现

在function中我们是不讲self的，因为我们告诉了函数给谁来完成这个工作,所以在定义外包工厂时
我们确认2个参数，robot color
然而再使用method时，我们却只告诉车间，color，那车间怎么知道给哪个机器人上色呢，是给normal，还是给另外的instance
因为我们在call这个method时，我们使用了normal_robor.paintarm()，所以paintarm这个method就知道是给这个normal_robot上色的
那么我们在python中要想使得instance.method（）正常工作，在class里编写时method时，就一定要把变量的第一个位子留出来，用来指代
未来call这个method的instance，也就是我们开始提到的，self指代的就是对象自己，哪个实例调用这个方法，那么self就表示这个实例
  
再说一个理解，类实例化后self既代表实例（对象）本身，理解self，那就把self当成实例对象的身份证，python的类不能直接使用
必须要实例化类，也就是创建实例对象才能发挥作用，每个实例对象都是独一无二的，它可以调用类的方法
属性，类就像灵魂附体一样，让实例（对象）有了自己（self)的功能
类中的实例方法中普遍都会有一个固定参数self      
这个参数就是代表着实例（对象）本身，就像是一个身份证，实例可以凭借身份证去调用类方法
就比如你个人是人类中的一个实例，那你可以凭借身份证去住酒店坐飞机等等        

        
        
        
        
        
        
        
        
        
        
        
        
        

class Person:
    def set_name(self, name):
        self.name = name

    def get_name(self):
        return self.name

# 创建两个Person实例
person1 = Person()
person2 = Person()

person1.set_name("Alice")
person2.set_name("Bob")

print(person1.get_name())  # 输出：Alice
print(person2.get_name())  # 输出：Bob

在上述示例中，self允许set_name和get_name
方法访问每个Person实例的name属性。如果没有self，这些方法将无法区分不同的实例。

以下是一个示例，演示如何定义和使用实例方法：
class Dog:
    def __init__(self, name, breed):
        self.name = name
        self.breed = breed

    def bark(self):
        return f"{self.name}（{self.breed}）汪汪叫"

# 创建一个Dog实例
my_dog = Dog("Buddy", "Golden Retriever")

# 调用实例方法
bark_sound = my_dog.bark()

print(bark_sound)  # 输出：Buddy（Golden Retriever）汪汪叫

在上述示例中，__init__方法是一个特殊的实例方法，用于初始化实例的属性
bark方法是另一个实例方法，使用self来访问实例的name和breed属性。


类方法和静态方法

除了实例方法，形如上面的bark，python还支持静态方法和类方法，这2种不需要self参数
类方法使用@classmethod装饰器定义，可以访问类级别的属性和方法，而不需要访问实例级别的属性
类方法的第一个参数通常是cls,表示类本身
class MathOperations:
    @classmethod
    def add(cls, x, y):
        return x + y

result = MathOperations.add(3, 5)
print(result)  # 输出：8

add方法是一个类方法，可以通过类名调用，而不需要创建类的实例。

静态方法我们使用@staticmethod装饰器，其不需要self 也不需要cls参数，静态方法通常用于与类相关的功能，不需要访问类的属性或方法
class StringUtils:
    @staticmethod
    def is_palindrome(s):
        s = s.lower().replace(" ", "")
        return s == s[::-1]

result = StringUtils.is_palindrome("A man a plan a canal Panama")
print(result)  # 输出：True

is_palindrome方法是一个静态方法，它与类相关，但不需要访问类的属性或方法。


类中，实例方法如何调用其他实例方法，类方法，静态方法
实例方法调用其他实例方法：使用self.方法名(参数)，或self.方法名(),直接调用
实例方法调用类方法，在实例方法内使用类名.方法名(),类名.方法名(参数)来调用 或者self.__class__.方法名()
实例方法调用静态方法，在实例方法内使用类名.方法名(),类名.方法名(参数)来调用 或者self.__class__.方法名()

类中，类方法如何调用其他3种方法
类方法中调用其他类方法，使用cls.类方法名() 或cls.类方法名(参数) 
类方法中调用其他静态方法，使用cls.静态方法名() 或cls.静态方法名(参数) 
类方法中调用其他实例方法，由于类方法不直接访问实例（即没有 self 参数），要调用实例方法需要先创建类的实例。你可以通过 cls() 创建一个新实例，然后调用实例方法
class MyClass:
    def instance_method(self):
        print("Instance Method called")
    
    @classmethod
    def class_method(cls):
        print("Class Method is calling Instance Method:")
        instance = cls()  # 创建类的一个实例
        instance.instance_method()  # 调用实例方法

# 调用类方法
MyClass.class_method()



类中静态方法如何调用其他静态方法，类方法，实例方法
调用其他静态方法  类名.静态方法名() 类名.静态方法名(参数) 
调用其他类方法 
第一种方案：类名.类方法名() 类名.类方法名(参数)
第二种方案：如果你希望静态方法更加通用，可以考虑将类作为参数传递给静态方法。
class MyClass:
    @classmethod
    def class_method(cls):
        print(f"Class Method of {cls.__name__} called")
    
    @staticmethod
    def static_method(some_class):
        print("Static Method is calling Class Method with passed class reference:")
        some_class.class_method()  # 使用传入的类引用调用类方法

# 调用静态方法并传递类引用
MyClass.static_method(MyClass)



调用其他实例方法
1.通过传递实例作为参数
class MyClass:
    def instance_method(self):
        print("Instance Method called")
    
    @staticmethod
    def static_method(instance):
        print("Static Method is calling Instance Method with passed instance:")
        instance.instance_method()  # 使用传入的实例调用实例方法

# 创建实例
obj = MyClass()

# 调用静态方法并传递实例
MyClass.static_method(obj)


第二种-在静态方法内创建-如果静态方法需要自己创建一个实例来调用实例方法，可以直接在静态方法内部创建实例
class MyClass:
    def instance_method(self):
        print("Instance Method called")
    
    @staticmethod
    def static_method():
        print("Static Method is creating an instance to call Instance Method:")
        obj = MyClass()  # 创建类的一个实例
        obj.instance_method()  # 调用实例方法

# 调用静态方法
MyClass.static_method()
"""